/**
 * Copyright 2016 andy
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.refactor.typer;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;


/**
 * Create by andy (https://github.com/andyxialm)
 * Create time: 16/10/30 20:10
 * Description : Typewriter EditText
 */
public class TyperEditText extends TextField implements ITyperControl {

    private static final int INTERVAL_CHARACTER_WRITE = 200;
    private static final int INTERVAL_PUNCTUATION_WRITE = 500;

    private int mCharacterWriteInterval;
    private int mPunctuationWriteInterval;
    private int mIndex;

    private boolean mWriting;
    private boolean mStop;
    private boolean mPause;

    private boolean mTouchable = false;
    private String mEditable;
    private OnWriteTextChangedListener mTextChangedListener;

    private RecycleWriteRunnable mRecycleWriteRunnable;

    private EventHandler mHandler;

    public TyperEditText(Context context) {
        this(context, null);
    }

    public TyperEditText(Context context, AttrSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public TyperEditText(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, "defStyleAttr");
        init(attrs);
    }

    @Override
    public void setText(int resId) {
        super.setText(resId);
    }

    public void setSourceText(String text) {
        mEditable = text;
    }

    public void setOnWriteTextChangedListener(OnWriteTextChangedListener l) {
        mTextChangedListener = l;
    }

    public boolean isWriting() {
        return mWriting;
    }

    public boolean isStop() {
        return mStop;
    }

    public boolean isPause() {
        return mPause;
    }

    @Override
    public void restart() {
        start();
    }

    @Override
    public void start() {
        if (mEditable == null || mEditable.length() == 0) {
            return;
        }
        clearStatus();
        setWriteStatus(true);
        recycleWrite(mIndex);
    }

    @Override
    public void stop() {
        mStop = true;
        mIndex = 0;
        mHandler.removeTask(mRecycleWriteRunnable);
    }

    @Override
    public void resume() {
        if (!isStop() && isPause()) {
            mStop = false;
            mPause = false;
            recycleWrite(++mIndex);
        }
    }

    @Override
    public void pause() {
        mPause = true;
        mHandler.removeTask(mRecycleWriteRunnable);
    }

    @Override
    public void release() {
        clearStatus();
        super.release();
    }

    private void init(AttrSet attrs) {
        mHandler = new EventHandler(EventRunner.current());
        if (attrs.getAttr("characterWriteInterval").isPresent()) {
            mCharacterWriteInterval = attrs.getAttr("characterWriteInterval").get().getIntegerValue();
        } else {
            mCharacterWriteInterval = INTERVAL_CHARACTER_WRITE;
        }
        if (attrs.getAttr("punctuationWriteInterval").isPresent()) {
            mPunctuationWriteInterval = attrs.getAttr("punctuationWriteInterval").get().getIntegerValue();
        } else {
            mPunctuationWriteInterval = INTERVAL_PUNCTUATION_WRITE;
        }
        attrs.getAttr("touchable").ifPresent(attr -> {
            mTouchable = attr.getBoolValue();
            setTouchFocusable(mTouchable);
        });
    }

    private void clearStatus() {
        mStop = false;
        mPause = false;
        mIndex = 0;
//        setText(null, BufferType.NORMAL);
        setText(null);
        mHandler.removeTask(mRecycleWriteRunnable);
    }

    private void setWriteStatus(boolean writing) {
        mWriting = writing;
    }

    private void recycleWrite(int index) {
        if (mEditable == null || mEditable.length() == 0 || index == mEditable.length()) {
            setWriteStatus(false);
            if (mTextChangedListener != null) {
                mTextChangedListener.onCompleted();
            }
            return;
        }

        if (mPause || mStop) {
            return;
        }

        if (mRecycleWriteRunnable == null) {
            mRecycleWriteRunnable = new RecycleWriteRunnable();
        }

        char curCharacter = mEditable.charAt(index);
        append(String.valueOf(curCharacter));

        int interval = isChinesePunctuation(curCharacter) ? mPunctuationWriteInterval : mCharacterWriteInterval;
        mHandler.postTask(mRecycleWriteRunnable, interval);
    }

    private boolean isChinesePunctuation(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS;
    }

    private class RecycleWriteRunnable implements Runnable {

        @Override
        public void run() {
            System.out.println("===RecycleWriteRunnable run===>");
            if (mTextChangedListener != null) {
                mTextChangedListener.onChanged(mIndex);
            }
            recycleWrite(++mIndex);
        }
    }
}
